{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "copyright"
      },
      "outputs": [],
      "source": [
        "# Copyright 2021 Google LLC\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "title:migration,new"
      },
      "source": [
        "# Vertex SDK: AutoML image classification model\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "install_aip"
      },
      "source": [
        "## Installation\n",
        "\n",
        "Install the latest (preview) version of Vertex SDK.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A_QVTkXr_i_r"
      },
      "outputs": [],
      "source": [
        "! pip3 install -U google-cloud-aiplatform --user"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "install_storage"
      },
      "source": [
        "Install the Google *cloud-storage* library as well.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "65SBis8d_i_s"
      },
      "outputs": [],
      "source": [
        "! pip3 install google-cloud-storage"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "restart"
      },
      "source": [
        "### Restart the Kernel\n",
        "\n",
        "Once you've installed the Vertex SDK and Google *cloud-storage*, you need to restart the notebook kernel so it can find the packages.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GIwKc4pk_i_t"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "if not os.getenv(\"AUTORUN\") and False:\n",
        "    # Automatically restart kernel after installs\n",
        "    import IPython\n",
        "\n",
        "    app = IPython.Application.instance()\n",
        "    app.kernel.do_shutdown(True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "before_you_begin"
      },
      "source": [
        "## Before you begin\n",
        "\n",
        "### GPU run-time\n",
        "\n",
        "*Make sure you're running this notebook in a GPU runtime if you have that option. In Colab, select* **Runtime > Change Runtime Type > GPU**\n",
        "\n",
        "### Set up your GCP project\n",
        "\n",
        "**The following steps are required, regardless of your notebook environment.**\n",
        "\n",
        "1. [Select or create a GCP project](https://console.cloud.google.com/cloud-resource-manager). When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
        "\n",
        "2. [Make sure that billing is enabled for your project.](https://cloud.google.com/billing/docs/how-to/modify-project)\n",
        "\n",
        "3. [Enable the Vertex APIs and Compute Engine APIs.](https://console.cloud.google.com/flows/enableapi?apiid=ml.googleapis.com,compute_component)\n",
        "\n",
        "4. [Google Cloud SDK](https://cloud.google.com/sdk) is already installed in Google Cloud Notebooks.\n",
        "\n",
        "5. Enter your project ID in the cell below. Then run the  cell to make sure the\n",
        "Cloud SDK uses the right project for all the commands in this notebook.\n",
        "\n",
        "**Note**: Jupyter runs lines prefixed with `!` as shell commands, and it interpolates Python variables prefixed with `$` into these commands.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "set_project_id"
      },
      "outputs": [],
      "source": [
        "PROJECT_ID = \"[your-project-id]\"  # @param {type:\"string\"}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "autoset_project_id"
      },
      "outputs": [],
      "source": [
        "if PROJECT_ID == \"\" or PROJECT_ID is None or PROJECT_ID == \"[your-project-id]\":\n",
        "    # Get your GCP project id from gcloud\n",
        "    shell_output = !gcloud config list --format 'value(core.project)' 2>/dev/null\n",
        "    PROJECT_ID = shell_output[0]\n",
        "    print(\"Project ID:\", PROJECT_ID)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "set_gcloud_project_id"
      },
      "outputs": [],
      "source": [
        "! gcloud config set project $PROJECT_ID"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "region"
      },
      "source": [
        "#### Region\n",
        "\n",
        "You can also change the `REGION` variable, which is used for operations\n",
        "throughout the rest of this notebook.  Below are regions supported for Vertex AI. We recommend when possible, to choose the region closest to you.\n",
        "\n",
        "- Americas: `us-central1`\n",
        "- Europe: `europe-west4`\n",
        "- Asia Pacific: `asia-east1`\n",
        "\n",
        "You cannot use a Multi-Regional Storage bucket for training with Vertex. Not all regions provide support for all Vertex services. For the latest support per region, see [Region support for Vertex AI services](https://cloud.google.com/vertex-ai/docs/general/locations)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6Xtp5tvK_i_y"
      },
      "outputs": [],
      "source": [
        "REGION = \"us-central1\"  # @param {type: \"string\"}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "timestamp"
      },
      "source": [
        "#### Timestamp\n",
        "\n",
        "If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a timestamp for each instance session, and append onto the name of resources which will be created in this tutorial.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d70An-Mg_i_2"
      },
      "outputs": [],
      "source": [
        "from datetime import datetime\n",
        "\n",
        "TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gcp_authenticate"
      },
      "source": [
        "### Authenticate your GCP account\n",
        "\n",
        "**If you are using Google Cloud Notebooks**, your environment is already\n",
        "authenticated. Skip this step.\n",
        "\n",
        "*Note: If you are on an Vertex notebook and run the cell, the cell knows to skip executing the authentication steps.*\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "chybg3Ap_i_2"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import sys\n",
        "\n",
        "# If you are running this notebook in Colab, run this cell and follow the\n",
        "# instructions to authenticate your Google Cloud account. This provides access\n",
        "# to your Cloud Storage bucket and lets you submit training jobs and prediction\n",
        "# requests.\n",
        "\n",
        "# If on Vertex, then don't execute this code\n",
        "if not os.path.exists(\"/opt/deeplearning/metadata/env_version\"):\n",
        "    if \"google.colab\" in sys.modules:\n",
        "        from google.colab import auth as google_auth\n",
        "\n",
        "        google_auth.authenticate_user()\n",
        "\n",
        "    # If you are running this tutorial in a notebook locally, replace the string\n",
        "    # below with the path to your service account key and run this cell to\n",
        "    # authenticate your Google Cloud account.\n",
        "    else:\n",
        "        %env GOOGLE_APPLICATION_CREDENTIALS your_path_to_credentials.json\n",
        "\n",
        "    # Log in to your account on Google Cloud\n",
        "    ! gcloud auth login"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bucket:batch_prediction"
      },
      "source": [
        "### Create a Cloud Storage bucket\n",
        "\n",
        "**The following steps are required, regardless of your notebook environment.**\n",
        "\n",
        "This tutorial is designed to use training data that is in a public Cloud Storage bucket and a local Cloud Storage bucket for your batch predictions. You may alternatively use your own training data that you have stored in a local Cloud Storage bucket.\n",
        "\n",
        "Set the name of your Cloud Storage bucket below. It must be unique across all Cloud Storage buckets.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bucket"
      },
      "outputs": [],
      "source": [
        "BUCKET_NAME = \"[your-bucket-name]\"  # @param {type:\"string\"}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "autoset_bucket"
      },
      "outputs": [],
      "source": [
        "if BUCKET_NAME == \"\" or BUCKET_NAME is None or BUCKET_NAME == \"[your-bucket-name]\":\n",
        "    BUCKET_NAME = PROJECT_ID + \"aip-\" + TIMESTAMP"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "create_bucket"
      },
      "source": [
        "**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qPPrwWpO_i_6"
      },
      "outputs": [],
      "source": [
        "! gsutil mb -l $REGION gs://$BUCKET_NAME"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "validate_bucket"
      },
      "source": [
        "Finally, validate access to your Cloud Storage bucket by examining its contents:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fn744B7x_i_7"
      },
      "outputs": [],
      "source": [
        "! gsutil ls -al gs://$BUCKET_NAME"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "setup_vars"
      },
      "source": [
        "### Set up variables\n",
        "\n",
        "Next, set up some variables used throughout the tutorial.\n",
        "### Import libraries and define constants\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "import_aip"
      },
      "source": [
        "#### Import Vertex SDK\n",
        "\n",
        "Import the Vertex SDK into our Python environment.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "97-XQPkv_i_7"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import sys\n",
        "import time\n",
        "\n",
        "from google.cloud.aiplatform import gapic as aip\n",
        "from google.protobuf import json_format\n",
        "from google.protobuf.json_format import MessageToJson, ParseDict\n",
        "from google.protobuf.struct_pb2 import Struct, Value"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aip_constants"
      },
      "source": [
        "#### Vertex AI constants\n",
        "\n",
        "Setup up the following constants for Vertex AI:\n",
        "\n",
        "- `API_ENDPOINT`: The Vertex AI API service endpoint for dataset, model, job, pipeline and endpoint services.\n",
        "- `API_PREDICT_ENDPOINT`: The Vertex AI API service endpoint for prediction.\n",
        "- `PARENT`: The Vertex AI location root path for dataset, model and endpoint resources.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kBBYqHEd_i_8"
      },
      "outputs": [],
      "source": [
        "# API Endpoint\n",
        "API_ENDPOINT = \"{}-aiplatform.googleapis.com\".format(REGION)\n",
        "\n",
        "# Vertex AI location root path for your dataset, model and endpoint resources\n",
        "PARENT = \"projects/\" + PROJECT_ID + \"/locations/\" + REGION"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "automl_constants:automl"
      },
      "source": [
        "#### AutoML constants\n",
        "\n",
        "Next, setup constants unique to AutoML image classification datasets and training:\n",
        "\n",
        "- Dataset Schemas: Tells the managed dataset service which type of dataset it is.\n",
        "- Data Labeling (Annotations) Schemas: Tells the managed dataset service how the data is labeled (annotated).\n",
        "- Dataset Training Schemas: Tells the managed pipelines service the task (e.g., classification) to train the model for.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "automl_constants:automl,icn"
      },
      "outputs": [],
      "source": [
        "# Image Dataset type\n",
        "IMAGE_SCHEMA = \"google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml\"\n",
        "# Image Labeling type\n",
        "IMPORT_SCHEMA_IMAGE_CLASSIFICATION = \"gs://google-cloud-aiplatform/schema/dataset/ioformat/image_classification_single_label_io_format_1.0.0.yaml\"\n",
        "# Image Training task\n",
        "TRAINING_IMAGE_CLASSIFICATION_SCHEMA = \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "clients"
      },
      "source": [
        "## Clients\n",
        "\n",
        "The Vertex SDK works as a client/server model. On your side (the Python script) you will create a client that sends requests and receives responses from the server (Vertex).\n",
        "\n",
        "You will use several clients in this tutorial, so set them all up upfront.\n",
        "\n",
        "- Dataset Service for managed datasets.\n",
        "- Model Service for managed models.\n",
        "- Pipeline Service for training.\n",
        "- Endpoint Service for deployment.\n",
        "- Job Service for batch jobs and custom training.\n",
        "- Prediction Service for serving. *Note*: Prediction has a different service endpoint.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "i2p2VYUz_i_-"
      },
      "outputs": [],
      "source": [
        "# client options same for all services\n",
        "client_options = {\"api_endpoint\": API_ENDPOINT}\n",
        "\n",
        "\n",
        "def create_dataset_client():\n",
        "    client = aip.DatasetServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "def create_model_client():\n",
        "    client = aip.ModelServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "def create_pipeline_client():\n",
        "    client = aip.PipelineServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "def create_endpoint_client():\n",
        "    client = aip.EndpointServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "def create_prediction_client():\n",
        "    client = aip.PredictionServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "def create_job_client():\n",
        "    client = aip.JobServiceClient(client_options=client_options)\n",
        "    return client\n",
        "\n",
        "\n",
        "clients = {}\n",
        "clients[\"dataset\"] = create_dataset_client()\n",
        "clients[\"model\"] = create_model_client()\n",
        "clients[\"pipeline\"] = create_pipeline_client()\n",
        "clients[\"endpoint\"] = create_endpoint_client()\n",
        "clients[\"prediction\"] = create_prediction_client()\n",
        "clients[\"job\"] = create_job_client()\n",
        "\n",
        "for client in clients.items():\n",
        "    print(client)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "import_file:flowers,csv,icn"
      },
      "outputs": [],
      "source": [
        "IMPORT_FILE = (\n",
        "    \"gs://cloud-samples-data/vision/automl_classification/flowers/all_data_v2.csv\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cBgFrDD1_i__"
      },
      "outputs": [],
      "source": [
        "! gsutil cat $IMPORT_FILE | head -n 10"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "datasets_create:migration,new,request"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10140303196_b88d3d6cec.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10172379554_b296050f82_n.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10172567486_2748826a8b.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10172636503_21bededa75_n.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/102841525_bd6628ae3c.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/1031799732_e7f4008c03.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10391248763_1d16681106_n.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10437754174_22ec990b77_m.jpg,daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10437770546_8bb6f7bdd3_m.jpg,daisy\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "create_a_dataset:migration"
      },
      "source": [
        "## Create a dataset\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "datasets_create:migration,new"
      },
      "source": [
        "### [projects.locations.datasets.create](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.datasets/create)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "request:migration"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RsM4amS9_jAB"
      },
      "outputs": [],
      "source": [
        "DATA_SCHEMA = IMAGE_SCHEMA\n",
        "\n",
        "dataset = {\n",
        "    \"display_name\": \"flowers_\" + TIMESTAMP,\n",
        "    \"metadata_schema_uri\": \"gs://\" + DATA_SCHEMA,\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.CreateDatasetRequest(\n",
        "            parent=PARENT,\n",
        "            dataset=dataset,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sPupiwqN_jAB"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"parent\": \"projects/migration-ucaip-training/locations/us-central1\",\n",
        "  \"dataset\": {\n",
        "    \"displayName\": \"flowers_20210226014942\",\n",
        "    \"metadataSchemaUri\": \"gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml\"\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "call:migration"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "datasets_create:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"dataset\"].create_dataset(\n",
        "    parent=PARENT,\n",
        "    dataset=dataset,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "response:migration"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "print:migration,new,response"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "datasets_create:migration,new,response"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/datasets/3094342379910463488\",\n",
        "  \"displayName\": \"flowers_20210226014942\",\n",
        "  \"metadataSchemaUri\": \"gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml\",\n",
        "  \"labels\": {\n",
        "    \"aiplatform.googleapis.com/dataset_metadata_schema\": \"IMAGE\"\n",
        "  },\n",
        "  \"metadata\": {\n",
        "    \"dataItemSchemaUri\": \"gs://google-cloud-aiplatform/schema/dataset/dataitem/image_1.0.0.yaml\"\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dataset_id:migration,new,response"
      },
      "outputs": [],
      "source": [
        "# The full unique ID for the dataset\n",
        "dataset_id = result.name\n",
        "# The short numeric ID for the dataset\n",
        "dataset_short_id = dataset_id.split(\"/\")[-1]\n",
        "\n",
        "print(dataset_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "datasets_import:migration,new"
      },
      "source": [
        "### [projects.locations.datasets.import](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.datasets/import)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oJtL08_Q_jAF"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "datasets_import:migration,new,request"
      },
      "outputs": [],
      "source": [
        "LABEL_SCHEMA = IMPORT_SCHEMA_IMAGE_CLASSIFICATION\n",
        "\n",
        "import_config = {\n",
        "    \"gcs_source\": {\n",
        "        \"uris\": [IMPORT_FILE],\n",
        "    },\n",
        "    \"import_schema_uri\": LABEL_SCHEMA,\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.ImportDataRequest(\n",
        "            name=dataset_short_id,\n",
        "            import_configs=[import_config],\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gC5MZDJc_jAG"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"3094342379910463488\",\n",
        "  \"importConfigs\": [\n",
        "    {\n",
        "      \"gcsSource\": {\n",
        "        \"uris\": [\n",
        "          \"gs://cloud-samples-data/vision/automl_classification/flowers/all_data_v2.csv\"\n",
        "        ]\n",
        "      },\n",
        "      \"importSchemaUri\": \"gs://google-cloud-aiplatform/schema/dataset/ioformat/image_classification_single_label_io_format_1.0.0.yaml\"\n",
        "    }\n",
        "  ]\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rnhDF5vW_jAG"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "datasets_import:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"dataset\"].import_data(\n",
        "    name=dataset_id,\n",
        "    import_configs=[import_config],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zQoFJ2K0_jAH"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "K7BjtQ3e_jAH"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "datasets_import:migration,new,response"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "train_a_model:migration"
      },
      "source": [
        "## Train a model\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "trainingpipelines_create:migration,new"
      },
      "source": [
        "### [projects.locations.trainingPipelines.create](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.trainingPipelines/create)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m5igPySU_jAJ"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trainingpipelines_create:migration,new,request,icn"
      },
      "outputs": [],
      "source": [
        "TRAINING_SCHEMA = TRAINING_IMAGE_CLASSIFICATION_SCHEMA\n",
        "\n",
        "task = Value(\n",
        "    struct_value=Struct(\n",
        "        fields={\n",
        "            \"multi_label\": Value(bool_value=False),\n",
        "            \"model_type\": Value(string_value=\"CLOUD\"),\n",
        "            \"budget_milli_node_hours\": Value(number_value=8000),\n",
        "            \"disable_early_stopping\": Value(bool_value=False),\n",
        "        }\n",
        "    )\n",
        ")\n",
        "\n",
        "training_pipeline = {\n",
        "    \"display_name\": \"flowers_\" + TIMESTAMP,\n",
        "    \"input_data_config\": {\n",
        "        \"dataset_id\": dataset_short_id,\n",
        "    },\n",
        "    \"model_to_upload\": {\n",
        "        \"display_name\": \"flowers_\" + TIMESTAMP,\n",
        "    },\n",
        "    \"training_task_definition\": TRAINING_SCHEMA,\n",
        "    \"training_task_inputs\": task,\n",
        "}\n",
        "\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.CreateTrainingPipelineRequest(\n",
        "            parent=PARENT,\n",
        "            training_pipeline=training_pipeline,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7IQ6Jp8E_jAJ"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"parent\": \"projects/migration-ucaip-training/locations/us-central1\",\n",
        "  \"trainingPipeline\": {\n",
        "    \"displayName\": \"flowers_20210226014942\",\n",
        "    \"inputDataConfig\": {\n",
        "      \"datasetId\": \"3094342379910463488\"\n",
        "    },\n",
        "    \"trainingTaskDefinition\": \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\",\n",
        "    \"trainingTaskInputs\": {\n",
        "      \"model_type\": \"CLOUD\",\n",
        "      \"budget_milli_node_hours\": 8000.0,\n",
        "      \"multi_label\": false,\n",
        "      \"disable_early_stopping\": false\n",
        "    },\n",
        "    \"modelToUpload\": {\n",
        "      \"displayName\": \"flowers_20210226014942\"\n",
        "    }\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xhuR86RL_jAK"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trainingpipelines_create:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"pipeline\"].create_training_pipeline(\n",
        "    parent=PARENT,\n",
        "    training_pipeline=training_pipeline,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S8zP7wju_jAL"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "print:migration,new,request"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "trainingpipelines_create:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/trainingPipelines/1112934465727889408\",\n",
        "  \"displayName\": \"flowers_20210226014942\",\n",
        "  \"inputDataConfig\": {\n",
        "    \"datasetId\": \"3094342379910463488\"\n",
        "  },\n",
        "  \"trainingTaskDefinition\": \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\",\n",
        "  \"trainingTaskInputs\": {\n",
        "    \"budgetMilliNodeHours\": \"8000\",\n",
        "    \"modelType\": \"CLOUD\"\n",
        "  },\n",
        "  \"modelToUpload\": {\n",
        "    \"displayName\": \"flowers_20210226014942\"\n",
        "  },\n",
        "  \"state\": \"PIPELINE_STATE_PENDING\",\n",
        "  \"createTime\": \"2021-02-26T02:11:57.377842Z\",\n",
        "  \"updateTime\": \"2021-02-26T02:11:57.377842Z\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "training_pipeline_id:migration,new,response"
      },
      "outputs": [],
      "source": [
        "# The full unique ID for the training pipeline\n",
        "training_pipeline_id = request.name\n",
        "# The short numeric ID for the training pipeline\n",
        "training_pipeline_short_id = training_pipeline_id.split(\"/\")[-1]\n",
        "\n",
        "print(training_pipeline_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "trainingpipelines_get:migration,new"
      },
      "source": [
        "### [projects.locations.trainingPipelines.get](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.trainingPipelines/get)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A3jRv70o_jAN"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trainingpipelines_get:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"pipeline\"].get_training_pipeline(\n",
        "    name=training_pipeline_id,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XC5I2xxt_jAN"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yXZnQR1t_jAO"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "trainingpipelines_get:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/trainingPipelines/1112934465727889408\",\n",
        "  \"displayName\": \"flowers_20210226014942\",\n",
        "  \"inputDataConfig\": {\n",
        "    \"datasetId\": \"3094342379910463488\"\n",
        "  },\n",
        "  \"trainingTaskDefinition\": \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\",\n",
        "  \"trainingTaskInputs\": {\n",
        "    \"budgetMilliNodeHours\": \"8000\",\n",
        "    \"modelType\": \"CLOUD\"\n",
        "  },\n",
        "  \"modelToUpload\": {\n",
        "    \"displayName\": \"flowers_20210226014942\"\n",
        "  },\n",
        "  \"state\": \"PIPELINE_STATE_PENDING\",\n",
        "  \"createTime\": \"2021-02-26T02:11:57.377842Z\",\n",
        "  \"updateTime\": \"2021-02-26T02:11:57.377842Z\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trainingpipelines_get:migration,new,wait"
      },
      "outputs": [],
      "source": [
        "while True:\n",
        "    response = clients[\"pipeline\"].get_training_pipeline(name=training_pipeline_id)\n",
        "    if response.state != aip.PipelineState.PIPELINE_STATE_SUCCEEDED:\n",
        "        print(\"Training job has not completed:\", response.state)\n",
        "        if response.state == aip.PipelineState.PIPELINE_STATE_FAILED:\n",
        "            break\n",
        "    else:\n",
        "        model_id = response.model_to_upload.name\n",
        "        print(\"Training Time:\", response.end_time - response.start_time)\n",
        "        break\n",
        "    time.sleep(60)\n",
        "\n",
        "print(model_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "evaluate_the_model:migration"
      },
      "source": [
        "## Evaluate the model\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_evaluations_list:migration,new"
      },
      "source": [
        "### [projects.locations.models.evaluations.list](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.models.evaluations/list)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ngn6qqVy_jAQ"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "models_evaluations_list:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"model\"].list_model_evaluations(\n",
        "    parent=model_id,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F0ryqI3F_jAQ"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AxEY7WFHj2YC"
      },
      "outputs": [],
      "source": [
        "import json\n",
        "\n",
        "model_evaluations = [json.loads(MessageToJson(me.__dict__[\"_pb\"])) for me in request]\n",
        "# The evaluation slice\n",
        "evaluation_slice = request.model_evaluations[0].name\n",
        "\n",
        "print(json.dumps(model_evaluations, indent=2))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_evaluations_list:migration,new,response,icn"
      },
      "source": [
        "*Example output*\n",
        "```\n",
        "[\n",
        "  {\n",
        "    \"name\": \"projects/116273516712/locations/us-central1/models/6656478578927992832/evaluations/8656839874550169600\",\n",
        "    \"metricsSchemaUri\": \"gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml\",\n",
        "    \"metrics\": {\n",
        "      \"confidenceMetrics\": [\n",
        "        {\n",
        "          \"precision\": 0.2,\n",
        "          \"recall\": 1.0\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.05,\n",
        "          \"recall\": 0.98092645,\n",
        "          \"precision\": 0.8910891\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.97275203,\n",
        "          \"confidenceThreshold\": 0.1,\n",
        "          \"precision\": 0.92248064\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.97002727,\n",
        "          \"confidenceThreshold\": 0.15,\n",
        "          \"precision\": 0.9295039\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.93421054,\n",
        "          \"confidenceThreshold\": 0.2,\n",
        "          \"recall\": 0.96730244\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.9465241,\n",
        "          \"recall\": 0.9645777,\n",
        "          \"confidenceThreshold\": 0.25\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.9645777,\n",
        "          \"precision\": 0.9516129,\n",
        "          \"confidenceThreshold\": 0.3\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.9567568,\n",
        "          \"recall\": 0.9645777,\n",
        "          \"confidenceThreshold\": 0.35\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.9592391,\n",
        "          \"recall\": 0.96185285,\n",
        "          \"confidenceThreshold\": 0.4\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.45,\n",
        "          \"precision\": 0.96185285,\n",
        "          \"recall\": 0.96185285\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.96185285,\n",
        "          \"recall\": 0.96185285,\n",
        "          \"confidenceThreshold\": 0.5\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.96185285,\n",
        "          \"confidenceThreshold\": 0.55,\n",
        "          \"precision\": 0.9644809\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.95640326,\n",
        "          \"confidenceThreshold\": 0.6,\n",
        "          \"precision\": 0.96428573\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.96694213,\n",
        "          \"confidenceThreshold\": 0.65,\n",
        "          \"recall\": 0.95640326\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.9536785,\n",
        "          \"confidenceThreshold\": 0.7,\n",
        "          \"precision\": 0.9695291\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.75,\n",
        "          \"precision\": 0.9719888,\n",
        "          \"recall\": 0.94550407\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.97720796,\n",
        "          \"confidenceThreshold\": 0.8,\n",
        "          \"recall\": 0.9346049\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.85,\n",
        "          \"recall\": 0.9318801,\n",
        "          \"precision\": 0.9771429\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.875,\n",
        "          \"recall\": 0.9291553,\n",
        "          \"precision\": 0.97988504\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.9,\n",
        "          \"precision\": 0.98255813,\n",
        "          \"recall\": 0.92098093\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.91,\n",
        "          \"precision\": 0.9825073,\n",
        "          \"recall\": 0.9182561\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.92,\n",
        "          \"recall\": 0.91553134,\n",
        "          \"precision\": 0.9882353\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.93,\n",
        "          \"recall\": 0.9128065,\n",
        "          \"precision\": 0.9882006\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.98813057,\n",
        "          \"confidenceThreshold\": 0.94,\n",
        "          \"recall\": 0.907357\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.990991,\n",
        "          \"recall\": 0.89918256,\n",
        "          \"confidenceThreshold\": 0.95\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.8855586,\n",
        "          \"precision\": 0.9938838,\n",
        "          \"confidenceThreshold\": 0.96\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 0.99380803,\n",
        "          \"recall\": 0.8746594,\n",
        "          \"confidenceThreshold\": 0.97\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.8692098,\n",
        "          \"precision\": 0.99376947,\n",
        "          \"confidenceThreshold\": 0.98\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.99,\n",
        "          \"precision\": 0.9968254,\n",
        "          \"recall\": 0.8555858\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.995,\n",
        "          \"recall\": 0.8310627,\n",
        "          \"precision\": 1.0\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.8256131,\n",
        "          \"precision\": 1.0,\n",
        "          \"confidenceThreshold\": 0.996\n",
        "        },\n",
        "        {\n",
        "          \"recall\": 0.8092643,\n",
        "          \"confidenceThreshold\": 0.997,\n",
        "          \"precision\": 1.0\n",
        "        },\n",
        "        {\n",
        "          \"confidenceThreshold\": 0.998,\n",
        "          \"precision\": 1.0,\n",
        "          \"recall\": 0.79019076\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 1.0,\n",
        "          \"recall\": 0.76021796,\n",
        "          \"confidenceThreshold\": 0.999\n",
        "        },\n",
        "        {\n",
        "          \"precision\": 1.0,\n",
        "          \"confidenceThreshold\": 1.0,\n",
        "          \"recall\": 0.22888283\n",
        "        }\n",
        "      ],\n",
        "      \"confusionMatrix\": {\n",
        "        \"rows\": [\n",
        "          [\n",
        "            80.0,\n",
        "            0.0,\n",
        "            0.0,\n",
        "            0.0,\n",
        "            0.0\n",
        "          ],\n",
        "          [\n",
        "            3.0,\n",
        "            85.0,\n",
        "            0.0,\n",
        "            2.0,\n",
        "            0.0\n",
        "          ],\n",
        "          [\n",
        "            0.0,\n",
        "            1.0,\n",
        "            67.0,\n",
        "            1.0,\n",
        "            1.0\n",
        "          ],\n",
        "          [\n",
        "            1.0,\n",
        "            1.0,\n",
        "            1.0,\n",
        "            60.0,\n",
        "            0.0\n",
        "          ],\n",
        "          [\n",
        "            3.0,\n",
        "            0.0,\n",
        "            0.0,\n",
        "            0.0,\n",
        "            61.0\n",
        "          ]\n",
        "        ],\n",
        "        \"annotationSpecs\": [\n",
        "          {\n",
        "            \"displayName\": \"tulips\",\n",
        "            \"id\": \"521556639170428928\"\n",
        "          },\n",
        "          {\n",
        "            \"displayName\": \"dandelion\",\n",
        "            \"id\": \"1674478143777275904\"\n",
        "          },\n",
        "          {\n",
        "            \"displayName\": \"sunflowers\",\n",
        "            \"id\": \"2827399648384122880\"\n",
        "          },\n",
        "          {\n",
        "            \"displayName\": \"daisy\",\n",
        "            \"id\": \"5133242657597816832\"\n",
        "          },\n",
        "          {\n",
        "            \"id\": \"7439085666811510784\",\n",
        "            \"displayName\": \"roses\"\n",
        "          }\n",
        "        ]\n",
        "      },\n",
        "      \"logLoss\": 0.04900711,\n",
        "      \"auPrc\": 0.99361706\n",
        "    },\n",
        "    \"createTime\": \"2021-02-26T02:36:30.247855Z\",\n",
        "    \"sliceDimensions\": [\n",
        "      \"annotationSpec\"\n",
        "    ]\n",
        "  }\n",
        "]\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_evaluations_get:migration,new"
      },
      "source": [
        "### [projects.locations.models.evaluations.get](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.models.evaluations/get)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_NXujm2U_jAR"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "models_evaluations_get:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"model\"].get_model_evaluation(\n",
        "    name=evaluation_slice,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0RLTdCfj_jAS"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HB2Uwhnq_jAS"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_evaluations_get:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/models/6656478578927992832/evaluations/8656839874550169600\",\n",
        "  \"metricsSchemaUri\": \"gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml\",\n",
        "  \"metrics\": {\n",
        "    \"logLoss\": 0.04900711,\n",
        "    \"confusionMatrix\": {\n",
        "      \"annotationSpecs\": [\n",
        "        {\n",
        "          \"displayName\": \"tulips\",\n",
        "          \"id\": \"521556639170428928\"\n",
        "        },\n",
        "        {\n",
        "          \"displayName\": \"dandelion\",\n",
        "          \"id\": \"1674478143777275904\"\n",
        "        },\n",
        "        {\n",
        "          \"displayName\": \"sunflowers\",\n",
        "          \"id\": \"2827399648384122880\"\n",
        "        },\n",
        "        {\n",
        "          \"displayName\": \"daisy\",\n",
        "          \"id\": \"5133242657597816832\"\n",
        "        },\n",
        "        {\n",
        "          \"id\": \"7439085666811510784\",\n",
        "          \"displayName\": \"roses\"\n",
        "        }\n",
        "      ],\n",
        "      \"rows\": [\n",
        "        [\n",
        "          80.0,\n",
        "          0.0,\n",
        "          0.0,\n",
        "          0.0,\n",
        "          0.0\n",
        "        ],\n",
        "        [\n",
        "          3.0,\n",
        "          85.0,\n",
        "          0.0,\n",
        "          2.0,\n",
        "          0.0\n",
        "        ],\n",
        "        [\n",
        "          0.0,\n",
        "          1.0,\n",
        "          67.0,\n",
        "          1.0,\n",
        "          1.0\n",
        "        ],\n",
        "        [\n",
        "          1.0,\n",
        "          1.0,\n",
        "          1.0,\n",
        "          60.0,\n",
        "          0.0\n",
        "        ],\n",
        "        [\n",
        "          3.0,\n",
        "          0.0,\n",
        "          0.0,\n",
        "          0.0,\n",
        "          61.0\n",
        "        ]\n",
        "      ]\n",
        "    },\n",
        "    \"auPrc\": 0.99361706,\n",
        "    \"confidenceMetrics\": [\n",
        "      {\n",
        "        \"recall\": 1.0,\n",
        "        \"precision\": 0.2\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.8910891,\n",
        "        \"confidenceThreshold\": 0.05,\n",
        "        \"recall\": 0.98092645\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.97275203,\n",
        "        \"precision\": 0.92248064,\n",
        "        \"confidenceThreshold\": 0.1\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.15,\n",
        "        \"precision\": 0.9295039,\n",
        "        \"recall\": 0.97002727\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.2,\n",
        "        \"precision\": 0.93421054,\n",
        "        \"recall\": 0.96730244\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.25,\n",
        "        \"recall\": 0.9645777,\n",
        "        \"precision\": 0.9465241\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9516129,\n",
        "        \"recall\": 0.9645777,\n",
        "        \"confidenceThreshold\": 0.3\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.35,\n",
        "        \"precision\": 0.9567568,\n",
        "        \"recall\": 0.9645777\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9592391,\n",
        "        \"recall\": 0.96185285,\n",
        "        \"confidenceThreshold\": 0.4\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.96185285,\n",
        "        \"precision\": 0.96185285,\n",
        "        \"confidenceThreshold\": 0.45\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.96185285,\n",
        "        \"recall\": 0.96185285,\n",
        "        \"confidenceThreshold\": 0.5\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9644809,\n",
        "        \"recall\": 0.96185285,\n",
        "        \"confidenceThreshold\": 0.55\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.6,\n",
        "        \"recall\": 0.95640326,\n",
        "        \"precision\": 0.96428573\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.95640326,\n",
        "        \"precision\": 0.96694213,\n",
        "        \"confidenceThreshold\": 0.65\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.7,\n",
        "        \"precision\": 0.9695291,\n",
        "        \"recall\": 0.9536785\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.94550407,\n",
        "        \"confidenceThreshold\": 0.75,\n",
        "        \"precision\": 0.9719888\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.9346049,\n",
        "        \"precision\": 0.97720796,\n",
        "        \"confidenceThreshold\": 0.8\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9771429,\n",
        "        \"confidenceThreshold\": 0.85,\n",
        "        \"recall\": 0.9318801\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.97988504,\n",
        "        \"confidenceThreshold\": 0.875,\n",
        "        \"recall\": 0.9291553\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.92098093,\n",
        "        \"confidenceThreshold\": 0.9,\n",
        "        \"precision\": 0.98255813\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.9182561,\n",
        "        \"confidenceThreshold\": 0.91,\n",
        "        \"precision\": 0.9825073\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9882353,\n",
        "        \"confidenceThreshold\": 0.92,\n",
        "        \"recall\": 0.91553134\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9882006,\n",
        "        \"confidenceThreshold\": 0.93,\n",
        "        \"recall\": 0.9128065\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.98813057,\n",
        "        \"recall\": 0.907357,\n",
        "        \"confidenceThreshold\": 0.94\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.990991,\n",
        "        \"confidenceThreshold\": 0.95,\n",
        "        \"recall\": 0.89918256\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9938838,\n",
        "        \"confidenceThreshold\": 0.96,\n",
        "        \"recall\": 0.8855586\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.8746594,\n",
        "        \"precision\": 0.99380803,\n",
        "        \"confidenceThreshold\": 0.97\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.98,\n",
        "        \"precision\": 0.99376947,\n",
        "        \"recall\": 0.8692098\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 0.9968254,\n",
        "        \"confidenceThreshold\": 0.99,\n",
        "        \"recall\": 0.8555858\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.995,\n",
        "        \"precision\": 1.0,\n",
        "        \"recall\": 0.8310627\n",
        "      },\n",
        "      {\n",
        "        \"precision\": 1.0,\n",
        "        \"recall\": 0.8256131,\n",
        "        \"confidenceThreshold\": 0.996\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.997,\n",
        "        \"precision\": 1.0,\n",
        "        \"recall\": 0.8092643\n",
        "      },\n",
        "      {\n",
        "        \"recall\": 0.79019076,\n",
        "        \"precision\": 1.0,\n",
        "        \"confidenceThreshold\": 0.998\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 0.999,\n",
        "        \"recall\": 0.76021796,\n",
        "        \"precision\": 1.0\n",
        "      },\n",
        "      {\n",
        "        \"confidenceThreshold\": 1.0,\n",
        "        \"precision\": 1.0,\n",
        "        \"recall\": 0.22888283\n",
        "      }\n",
        "    ]\n",
        "  },\n",
        "  \"createTime\": \"2021-02-26T02:36:30.247855Z\",\n",
        "  \"sliceDimensions\": [\n",
        "    \"annotationSpec\"\n",
        "  ]\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "make_batch_predictions:migration"
      },
      "source": [
        "## Make batch predictions\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "make_batch_prediction_file:migration,new"
      },
      "source": [
        "### Make a batch prediction file\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "get_test_items:automl,icn,csv"
      },
      "outputs": [],
      "source": [
        "test_items = !gsutil cat $IMPORT_FILE | head -n2\n",
        "\n",
        "if len(str(test_items[0]).split(\",\")) == 3:\n",
        "    _, test_item_1, test_label_1 = str(test_items[0]).split(\",\")\n",
        "    _, test_item_2, test_label_2 = str(test_items[1]).split(\",\")\n",
        "else:\n",
        "    test_item_1, test_label_1 = str(test_items[0]).split(\",\")\n",
        "    test_item_2, test_label_2 = str(test_items[1]).split(\",\")\n",
        "\n",
        "print(test_item_1, test_label_1)\n",
        "print(test_item_2, test_label_2)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rQkHuZbk_jAV"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg daisy\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/10140303196_b88d3d6cec.jpg daisy\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "copy_test_items:automl,image,batch_prediction"
      },
      "outputs": [],
      "source": [
        "file_1 = test_item_1.split(\"/\")[-1]\n",
        "file_2 = test_item_2.split(\"/\")[-1]\n",
        "\n",
        "! gsutil cp $test_item_1 gs://$BUCKET_NAME/$file_1\n",
        "! gsutil cp $test_item_2 gs://$BUCKET_NAME/$file_2\n",
        "\n",
        "test_item_1 = \"gs://\" + BUCKET_NAME + \"/\" + file_1\n",
        "test_item_2 = \"gs://\" + BUCKET_NAME + \"/\" + file_2"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "make_batch_file:automl,image"
      },
      "source": [
        "### Make the batch input file\n",
        "\n",
        "Let's now make a batch input file, which you will store in your local Cloud Storage bucket. The batch input file can be either CSV or JSONL. You will use JSONL in this tutorial. For JSONL file, you make one dictionary entry per line for each data item (instance). The dictionary contains the key/value pairs:\n",
        "\n",
        "- `content`: The Cloud Storage path to the image.\n",
        "- `mime_type`: The content type. In our example, it is an `jpeg` file.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bxjbyhI3_jAW"
      },
      "outputs": [],
      "source": [
        "import json\n",
        "\n",
        "import tensorflow as tf\n",
        "\n",
        "gcs_input_uri = \"gs://\" + BUCKET_NAME + \"/test.jsonl\"\n",
        "with tf.io.gfile.GFile(gcs_input_uri, \"w\") as f:\n",
        "    data = {\"content\": test_item_1, \"mime_type\": \"image/jpeg\"}\n",
        "    f.write(json.dumps(data) + \"\\n\")\n",
        "    data = {\"content\": test_item_2, \"mime_type\": \"image/jpeg\"}\n",
        "    f.write(json.dumps(data) + \"\\n\")\n",
        "\n",
        "print(gcs_input_uri)\n",
        "!gsutil cat $gcs_input_uri"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MC8D11Xe_jAW"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://migration-ucaip-trainingaip-20210226014942/test.jsonl\n",
        "{\"content\": \"gs://migration-ucaip-trainingaip-20210226014942/100080576_f52e8ee070_n.jpg\", \"mime_type\": \"image/jpeg\"}\n",
        "{\"content\": \"gs://migration-ucaip-trainingaip-20210226014942/10140303196_b88d3d6cec.jpg\", \"mime_type\": \"image/jpeg\"}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "batchpredictionjobs_create:migration,new"
      },
      "source": [
        "### [projects.locations.batchPredictionJobs.create](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.batchPredictionJobs/create)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "htIpycBi_jAX"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "batchpredictionjobs_create:migration,new,request,icn"
      },
      "outputs": [],
      "source": [
        "parameters = {\"confidenceThreshold\": 0.5, \"maxPredictions\": 2}\n",
        "\n",
        "batch_prediction_job = {\n",
        "    \"display_name\": \"flowers_\" + TIMESTAMP,\n",
        "    \"model\": model_id,\n",
        "    \"input_config\": {\n",
        "        \"instances_format\": \"jsonl\",\n",
        "        \"gcs_source\": {\n",
        "            \"uris\": [gcs_input_uri],\n",
        "        },\n",
        "    },\n",
        "    \"model_parameters\": json_format.ParseDict(parameters, Value()),\n",
        "    \"output_config\": {\n",
        "        \"predictions_format\": \"jsonl\",\n",
        "        \"gcs_destination\": {\n",
        "            \"output_uri_prefix\": \"gs://\" + f\"{BUCKET_NAME}/batch_output/\",\n",
        "        },\n",
        "    },\n",
        "    \"dedicated_resources\": {\n",
        "        \"machine_spec\": {\n",
        "            \"machine_type\": \"n1-standard-2\",\n",
        "            \"accelerator_type\": 0,\n",
        "        },\n",
        "        \"starting_replica_count\": 1,\n",
        "        \"max_replica_count\": 1,\n",
        "    },\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.CreateBatchPredictionJobRequest(\n",
        "            parent=PARENT,\n",
        "            batch_prediction_job=batch_prediction_job,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cXThRLYf_jAX"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"parent\": \"projects/migration-ucaip-training/locations/us-central1\",\n",
        "  \"batchPredictionJob\": {\n",
        "    \"displayName\": \"flowers_20210226014942\",\n",
        "    \"model\": \"projects/116273516712/locations/us-central1/models/6656478578927992832\",\n",
        "    \"inputConfig\": {\n",
        "      \"instancesFormat\": \"jsonl\",\n",
        "      \"gcsSource\": {\n",
        "        \"uris\": [\n",
        "          \"gs://migration-ucaip-trainingaip-20210226014942/test.jsonl\"\n",
        "        ]\n",
        "      }\n",
        "    },\n",
        "    \"modelParameters\": {\n",
        "      \"confidenceThreshold\": 0.5,\n",
        "      \"maxPredictions\": 2.0\n",
        "    },\n",
        "    \"outputConfig\": {\n",
        "      \"predictionsFormat\": \"jsonl\",\n",
        "      \"gcsDestination\": {\n",
        "        \"outputUriPrefix\": \"gs://migration-ucaip-trainingaip-20210226014942/batch_output/\"\n",
        "      }\n",
        "    },\n",
        "    \"dedicatedResources\": {\n",
        "      \"machineSpec\": {\n",
        "        \"machineType\": \"n1-standard-2\"\n",
        "      },\n",
        "      \"startingReplicaCount\": 1,\n",
        "      \"maxReplicaCount\": 1\n",
        "    }\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8QO3y-36_jAY"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "batchpredictionjobs_create:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"job\"].create_batch_prediction_job(\n",
        "    parent=PARENT,\n",
        "    batch_prediction_job=batch_prediction_job,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DmClxRYK_jAY"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "118r_5MI_jAY"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "batchpredictionjobs_create:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/batchPredictionJobs/7156765165659095040\",\n",
        "  \"displayName\": \"flowers_20210226014942\",\n",
        "  \"model\": \"projects/116273516712/locations/us-central1/models/6656478578927992832\",\n",
        "  \"inputConfig\": {\n",
        "    \"instancesFormat\": \"jsonl\",\n",
        "    \"gcsSource\": {\n",
        "      \"uris\": [\n",
        "        \"gs://migration-ucaip-trainingaip-20210226014942/test.jsonl\"\n",
        "      ]\n",
        "    }\n",
        "  },\n",
        "  \"modelParameters\": {\n",
        "    \"maxPredictions\": 2.0,\n",
        "    \"confidenceThreshold\": 0.5\n",
        "  },\n",
        "  \"outputConfig\": {\n",
        "    \"predictionsFormat\": \"jsonl\",\n",
        "    \"gcsDestination\": {\n",
        "      \"outputUriPrefix\": \"gs://migration-ucaip-trainingaip-20210226014942/batch_output/\"\n",
        "    }\n",
        "  },\n",
        "  \"state\": \"JOB_STATE_PENDING\",\n",
        "  \"completionStats\": {\n",
        "    \"incompleteCount\": \"-1\"\n",
        "  },\n",
        "  \"createTime\": \"2021-02-26T02:36:52.483588Z\",\n",
        "  \"updateTime\": \"2021-02-26T02:36:52.483588Z\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "batch_job_id:migration,new,response"
      },
      "outputs": [],
      "source": [
        "# The fully qualified ID for the batch job\n",
        "batch_job_id = request.name\n",
        "# The short numeric ID for the batch job\n",
        "batch_job_short_id = batch_job_id.split(\"/\")[-1]\n",
        "\n",
        "print(batch_job_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "batchpredictionjobs_get:migration,new"
      },
      "source": [
        "### [projects.locations.batchPredictionJobs.get](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.batchPredictionJobs/get)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aSE_wqES_jAa"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "batchpredictionjobs_get:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"job\"].get_batch_prediction_job(\n",
        "    name=batch_job_id,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LUy0NIF__jAa"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "a1CtiIM5_jAa"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "batchpredictionjobs_get:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/batchPredictionJobs/7156765165659095040\",\n",
        "  \"displayName\": \"flowers_20210226014942\",\n",
        "  \"model\": \"projects/116273516712/locations/us-central1/models/6656478578927992832\",\n",
        "  \"inputConfig\": {\n",
        "    \"instancesFormat\": \"jsonl\",\n",
        "    \"gcsSource\": {\n",
        "      \"uris\": [\n",
        "        \"gs://migration-ucaip-trainingaip-20210226014942/test.jsonl\"\n",
        "      ]\n",
        "    }\n",
        "  },\n",
        "  \"modelParameters\": {\n",
        "    \"confidenceThreshold\": 0.5,\n",
        "    \"maxPredictions\": 2.0\n",
        "  },\n",
        "  \"outputConfig\": {\n",
        "    \"predictionsFormat\": \"jsonl\",\n",
        "    \"gcsDestination\": {\n",
        "      \"outputUriPrefix\": \"gs://migration-ucaip-trainingaip-20210226014942/batch_output/\"\n",
        "    }\n",
        "  },\n",
        "  \"state\": \"JOB_STATE_PENDING\",\n",
        "  \"completionStats\": {\n",
        "    \"incompleteCount\": \"-1\"\n",
        "  },\n",
        "  \"createTime\": \"2021-02-26T02:36:52.483588Z\",\n",
        "  \"updateTime\": \"2021-02-26T02:36:52.483588Z\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "batchpredictionjobs_get:migration,new,wait"
      },
      "outputs": [],
      "source": [
        "def get_latest_predictions(gcs_out_dir):\n",
        "    \"\"\" Get the latest prediction subfolder using the timestamp in the subfolder name\"\"\"\n",
        "    folders = !gsutil ls $gcs_out_dir\n",
        "    latest = \"\"\n",
        "    for folder in folders:\n",
        "        subfolder = folder.split(\"/\")[-2]\n",
        "        if subfolder.startswith(\"prediction-\"):\n",
        "            if subfolder > latest:\n",
        "                latest = folder[:-1]\n",
        "    return latest\n",
        "\n",
        "\n",
        "while True:\n",
        "    response = clients[\"job\"].get_batch_prediction_job(name=batch_job_id)\n",
        "    if response.state != aip.JobState.JOB_STATE_SUCCEEDED:\n",
        "        print(\"The job has not completed:\", response.state)\n",
        "        if response.state == aip.JobState.JOB_STATE_FAILED:\n",
        "            break\n",
        "    else:\n",
        "        folder = get_latest_predictions(\n",
        "            response.output_config.gcs_destination.output_uri_prefix\n",
        "        )\n",
        "        ! gsutil ls $folder/prediction*.jsonl\n",
        "\n",
        "        ! gsutil cat $folder/prediction*.jsonl\n",
        "        break\n",
        "    time.sleep(60)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "batchpredictionjobs_get:migration,new,wait,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://migration-ucaip-trainingaip-20210226014942/batch_output/prediction-flowers_20210226014942-2021-02-26T02:36:52.355258Z/predictions_00001.jsonl\n",
        "{\"instance\":{\"content\":\"gs://migration-ucaip-trainingaip-20210226014942/10140303196_b88d3d6cec.jpg\",\"mimeType\":\"image/jpeg\"},\"prediction\":{\"ids\":[\"5133242657597816832\"],\"displayNames\":[\"daisy\"],\"confidences\":[0.9999988]}}\n",
        "{\"instance\":{\"content\":\"gs://migration-ucaip-trainingaip-20210226014942/100080576_f52e8ee070_n.jpg\",\"mimeType\":\"image/jpeg\"},\"prediction\":{\"ids\":[\"5133242657597816832\"],\"displayNames\":[\"daisy\"],\"confidences\":[0.99999106]}}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "make_online_predictions:migration"
      },
      "source": [
        "## Make online predictions\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_create:migration,new"
      },
      "source": [
        "### [projects.locations.endpoints.create](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.endpoints/create)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ph5S0j4v_jAc"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_create:migration,new,request"
      },
      "outputs": [],
      "source": [
        "endpoint = {\"display_name\": \"flowers_\" + TIMESTAMP}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.CreateEndpointRequest(\n",
        "            parent=PARENT,\n",
        "            endpoint=endpoint,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cwUNXZaz_jAd"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"parent\": \"projects/migration-ucaip-training/locations/us-central1\",\n",
        "  \"endpoint\": {\n",
        "    \"displayName\": \"flowers_20210226014942\"\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yjsSo1cM_jAd"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_create:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"endpoint\"].create_endpoint(\n",
        "    parent=PARENT,\n",
        "    endpoint=endpoint,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ijvF_HGd_jAe"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "G4Gd_8oI_jAe"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_create:migration,new,response"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/endpoints/3440574193450614784\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoint_id:migration,new,response"
      },
      "outputs": [],
      "source": [
        "# The full unique ID for the endpoint\n",
        "endpoint_id = result.name\n",
        "# The short numeric ID for the endpoint\n",
        "endpoint_short_id = endpoint_id.split(\"/\")[-1]\n",
        "\n",
        "print(endpoint_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_deploymodel:migration,new"
      },
      "source": [
        "### [projects.locations.endpoints.deployModel](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.endpoints/deployModel)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NFIRI0XT_jAf"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_deploymodel:migration,new,request"
      },
      "outputs": [],
      "source": [
        "deployed_model = {\n",
        "    \"model\": model_id,\n",
        "    \"display_name\": \"flowers_\" + TIMESTAMP,\n",
        "    \"automatic_resources\": {\"min_replica_count\": 1, \"max_replica_count\": 1},\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.DeployModelRequest(\n",
        "            endpoint=endpoint_id,\n",
        "            deployed_model=deployed_model,\n",
        "            traffic_split={\n",
        "                \"0\": 100,\n",
        "            },\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g8FThQHT_jAg"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"endpoint\": \"projects/116273516712/locations/us-central1/endpoints/3440574193450614784\",\n",
        "  \"deployedModel\": {\n",
        "    \"model\": \"projects/116273516712/locations/us-central1/models/6656478578927992832\",\n",
        "    \"displayName\": \"flowers_20210226014942\",\n",
        "    \"automaticResources\": {\n",
        "      \"minReplicaCount\": 1,\n",
        "      \"maxReplicaCount\": 1\n",
        "    }\n",
        "  },\n",
        "  \"trafficSplit\": {\n",
        "    \"0\": 100\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c3_4BVyW_jAh"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_deploymodel:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"endpoint\"].deploy_model(\n",
        "    endpoint=endpoint_id,\n",
        "    deployed_model=deployed_model,\n",
        "    traffic_split={\n",
        "        \"0\": 100,\n",
        "    },\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7NmySa8R_jAh"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "v6qJ5zcN_jAi"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_deploymodel:migration,new,response"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"deployedModel\": {\n",
        "    \"id\": \"5165312113245159424\"\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "deployed_model_id:migration,new,response"
      },
      "outputs": [],
      "source": [
        "# The unique ID for the deployed model\n",
        "deployed_model_id = result.deployed_model.id\n",
        "\n",
        "print(deployed_model_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_predict:migration,new"
      },
      "source": [
        "### [projects.locations.endpoints.predict](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.endpoints/predict)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "941306da2e54"
      },
      "source": [
        "#### Prepare file for online prediction"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "get_test_item:automl,icn,csv"
      },
      "outputs": [],
      "source": [
        "import base64\n",
        "\n",
        "import tensorflow as tf\n",
        "\n",
        "test_item = !gsutil cat $IMPORT_FILE | head -n1\n",
        "\n",
        "if len(str(test_item[0]).split(\",\")) == 3:\n",
        "    _, test_item, test_label = str(test_item[0]).split(\",\")\n",
        "else:\n",
        "    test_item, test_label = str(test_item[0]).split(\",\")\n",
        "\n",
        "print(test_item, test_label)\n",
        "\n",
        "with tf.io.gfile.GFile(test_item, \"rb\") as f:\n",
        "    content = f.read()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_undeploymodel:migration,new,response"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg daisy\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6fb84nKh_jAk"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_predict:migration,new,request,icn"
      },
      "outputs": [],
      "source": [
        "parameters_dict = {\n",
        "    \"confidenceThreshold\": 0.5,\n",
        "    \"maxPredictions\": 2,\n",
        "}\n",
        "parameters = json_format.ParseDict(parameters_dict, Value())\n",
        "\n",
        "# The format of each instance should conform to the deployed model's prediction input schema.\n",
        "instances_list = [{\"content\": base64.b64encode(content).decode(\"utf-8\")}]\n",
        "instances = [json_format.ParseDict(s, Value()) for s in instances_list]\n",
        "\n",
        "request = aip.PredictRequest(\n",
        "    endpoint=endpoint_id,\n",
        "    parameters=parameters,\n",
        ")\n",
        "request.instances.append(instances)\n",
        "\n",
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0SDSqWD3UILw"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"endpoint\": \"projects/116273516712/locations/us-central1/endpoints/3440574193450614784\",\n",
        "  \"instances\": [\n",
        "    [\n",
        "      {\n",
        "        \"content\": \"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\"\n",
        "      }\n",
        "    ]\n",
        "  ],\n",
        "  \"parameters\": {\n",
        "    \"maxPredictions\": 2.0,\n",
        "    \"confidenceThreshold\": 0.5\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "h6IskqWe_jAo"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_predict:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"prediction\"].predict(\n",
        "    endpoint=endpoint_id,\n",
        "    instances=instances,\n",
        "    parameters=parameters,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KHf2BSMR_jAo"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "egOqdNyN_jAp"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_predict:migration,new,response,icn"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"predictions\": [\n",
        "    {\n",
        "      \"confidences\": [\n",
        "        0.999991059\n",
        "      ],\n",
        "      \"ids\": [\n",
        "        \"5133242657597816832\"\n",
        "      ],\n",
        "      \"displayNames\": [\n",
        "        \"daisy\"\n",
        "      ]\n",
        "    }\n",
        "  ],\n",
        "  \"deployedModelId\": \"5165312113245159424\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "endpoints_undeploymodel:migration,new"
      },
      "source": [
        "### [projects.locations.endpoints.undeployModel](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.endpoints/undeployModel)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KrVZz6Uw_jAp"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "endpoints_undeploymodel:migration,new,call"
      },
      "outputs": [],
      "source": [
        "request = clients[\"endpoint\"].undeploy_model(\n",
        "    endpoint=endpoint_id,\n",
        "    deployed_model_id=deployed_model_id,\n",
        "    traffic_split={},\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wvFK-kir_jAq"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GvajSw-Y_jAq"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MPWmXvPVUIL2"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "train_and_export_edge_model:migration"
      },
      "source": [
        "## Train and export an Edge model\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5bwEQMKT_jAr"
      },
      "source": [
        "### [projects.locations.trainingPipelines.create](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.trainingPipelines/create)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LOsxiKj4_jAs"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trainingpipelines_create:migration,new,request,icn,edge"
      },
      "outputs": [],
      "source": [
        "task = Value(\n",
        "    struct_value=Struct(\n",
        "        fields={\n",
        "            \"disable_early_stopping\": Value(bool_value=False),\n",
        "            \"model_type\": Value(string_value=\"MOBILE_TF_VERSATILE_1\"),\n",
        "            \"multi_label\": Value(bool_value=False),\n",
        "            \"budget_milli_node_hours\": Value(number_value=8000),\n",
        "        }\n",
        "    )\n",
        ")\n",
        "\n",
        "training_pipeline = {\n",
        "    \"display_name\": \"flowers_edge_\" + TIMESTAMP,\n",
        "    \"input_data_config\": {\n",
        "        \"dataset_id\": dataset_short_id,\n",
        "        \"fraction_split\": {\n",
        "            \"training_fraction\": 0.8,\n",
        "            \"validation_fraction\": 0.1,\n",
        "            \"test_fraction\": 0.1,\n",
        "        },\n",
        "    },\n",
        "    \"model_to_upload\": {\n",
        "        \"display_name\": \"flowers_edge_\" + TIMESTAMP,\n",
        "    },\n",
        "    \"training_task_definition\": TRAINING_SCHEMA,\n",
        "    \"training_task_inputs\": task,\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.CreateTrainingPipelineRequest(\n",
        "            parent=PARENT,\n",
        "            training_pipeline=training_pipeline,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IREmlyf5_jAs"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"parent\": \"projects/migration-ucaip-training/locations/us-central1\",\n",
        "  \"trainingPipeline\": {\n",
        "    \"displayName\": \"flowers_edge_20210226014942\",\n",
        "    \"inputDataConfig\": {\n",
        "      \"datasetId\": \"3094342379910463488\",\n",
        "      \"fractionSplit\": {\n",
        "        \"trainingFraction\": 0.8,\n",
        "        \"validationFraction\": 0.1,\n",
        "        \"testFraction\": 0.1\n",
        "      }\n",
        "    },\n",
        "    \"trainingTaskDefinition\": \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\",\n",
        "    \"trainingTaskInputs\": {\n",
        "      \"multi_label\": false,\n",
        "      \"disable_early_stopping\": false,\n",
        "      \"budget_milli_node_hours\": 8000.0,\n",
        "      \"model_type\": \"MOBILE_TF_VERSATILE_1\"\n",
        "    },\n",
        "    \"modelToUpload\": {\n",
        "      \"displayName\": \"flowers_edge_20210226014942\"\n",
        "    }\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PWMEUCbF_jAt"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T_8-j8nx_jAt"
      },
      "outputs": [],
      "source": [
        "request = clients[\"pipeline\"].create_training_pipeline(\n",
        "    parent=PARENT,\n",
        "    training_pipeline=training_pipeline,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OalQ6m9P_jAu"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "X6gz-Nx8_jAu"
      },
      "outputs": [],
      "source": [
        "print(MessageToJson(request.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "trainingpipelines_create:migration,new,response,icn,edge"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/trainingPipelines/7472017139575029760\",\n",
        "  \"displayName\": \"flowers_edge_20210226014942\",\n",
        "  \"inputDataConfig\": {\n",
        "    \"datasetId\": \"3094342379910463488\",\n",
        "    \"fractionSplit\": {\n",
        "      \"trainingFraction\": 0.8,\n",
        "      \"validationFraction\": 0.1,\n",
        "      \"testFraction\": 0.1\n",
        "    }\n",
        "  },\n",
        "  \"trainingTaskDefinition\": \"gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_image_classification_1.0.0.yaml\",\n",
        "  \"trainingTaskInputs\": {\n",
        "    \"modelType\": \"MOBILE_TF_VERSATILE_1\",\n",
        "    \"budgetMilliNodeHours\": \"8000\"\n",
        "  },\n",
        "  \"modelToUpload\": {\n",
        "    \"displayName\": \"flowers_edge_20210226014942\"\n",
        "  },\n",
        "  \"state\": \"PIPELINE_STATE_PENDING\",\n",
        "  \"createTime\": \"2021-02-26T03:34:33.436419Z\",\n",
        "  \"updateTime\": \"2021-02-26T03:34:33.436419Z\"\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QidD3YK5_jAv"
      },
      "outputs": [],
      "source": [
        "# The full unique ID for the training pipeline\n",
        "training_pipeline_edge_id = request.name\n",
        "# The short numeric ID for the training pipeline\n",
        "training_pipeline_edge_short_id = training_pipeline_edge_id.split(\"/\")[-1]\n",
        "\n",
        "print(training_pipeline_edge_id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vukYRydw_jAv"
      },
      "outputs": [],
      "source": [
        "while True:\n",
        "    response = clients[\"pipeline\"].get_training_pipeline(name=training_pipeline_edge_id)\n",
        "    if response.state != aip.PipelineState.PIPELINE_STATE_SUCCEEDED:\n",
        "        print(\"Training job has not completed:\", response.state)\n",
        "        if response.state == aip.PipelineState.PIPELINE_STATE_FAILED:\n",
        "            break\n",
        "    else:\n",
        "        model_edge_id = response.model_to_upload.name\n",
        "        print(\"Training Time:\", response.end_time - response.start_time)\n",
        "        break\n",
        "    time.sleep(60)\n",
        "\n",
        "print(model_edge_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_export:migration,new"
      },
      "source": [
        "### [projects.locations.models.export](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.models/export)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lqJoqYMI_jAv"
      },
      "source": [
        "#### Request\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "models_export:migration,new,request,edge"
      },
      "outputs": [],
      "source": [
        "model_output_config = {\n",
        "    \"export_format_id\": \"tflite\",\n",
        "    \"artifact_destination\": {\n",
        "        \"output_uri_prefix\": \"gs://\" + f\"{BUCKET_NAME}/export/\",\n",
        "    },\n",
        "}\n",
        "\n",
        "print(\n",
        "    MessageToJson(\n",
        "        aip.ExportModelRequest(\n",
        "            name=model_edge_id,\n",
        "            output_config=model_output_config,\n",
        "        ).__dict__[\"_pb\"]\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WRi2WK4o_jAw"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{\n",
        "  \"name\": \"projects/116273516712/locations/us-central1/models/1204871229996007424\",\n",
        "  \"outputConfig\": {\n",
        "    \"exportFormatId\": \"tflite\",\n",
        "    \"artifactDestination\": {\n",
        "      \"outputUriPrefix\": \"gs://migration-ucaip-trainingaip-20210226014942/export/\"\n",
        "    }\n",
        "  }\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v6isqzPQ_jAw"
      },
      "source": [
        "#### Call\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "models_export:migration,new,call,edge"
      },
      "outputs": [],
      "source": [
        "request = clients[\"model\"].export_model(\n",
        "    name=model_edge_id,\n",
        "    output_config=model_output_config,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZCyd1qAb_jAx"
      },
      "source": [
        "#### Response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xRGA3tcC_jAx"
      },
      "outputs": [],
      "source": [
        "result = request.result()\n",
        "\n",
        "print(MessageToJson(result.__dict__[\"_pb\"]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "models_export:migration,new,response,edge"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "{}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nQAiuIAc_jAx"
      },
      "outputs": [],
      "source": [
        "model_export_dir = model_output_config[\"artifact_destination\"][\"output_uri_prefix\"]\n",
        "\n",
        "! gsutil ls -r $model_export_dir"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fCG8yqkW_jAy"
      },
      "source": [
        "*Example output*:\n",
        "```\n",
        "gs://migration-ucaip-trainingaip-20210226014942/export/:\n",
        "\n",
        "gs://migration-ucaip-trainingaip-20210226014942/export/model-1204871229996007424/:\n",
        "\n",
        "gs://migration-ucaip-trainingaip-20210226014942/export/model-1204871229996007424/tflite/:\n",
        "\n",
        "gs://migration-ucaip-trainingaip-20210226014942/export/model-1204871229996007424/tflite/2021-02-26T04:43:08.209439Z/:\n",
        "gs://migration-ucaip-trainingaip-20210226014942/export/model-1204871229996007424/tflite/2021-02-26T04:43:08.209439Z/model.tflite\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cleanup:migration,new"
      },
      "source": [
        "# Cleaning up\n",
        "\n",
        "To clean up all GCP resources used in this project, you can [delete the GCP\n",
        "project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects) you used for the tutorial.\n",
        "\n",
        "Otherwise, you can delete the individual resources you created in this tutorial.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aoJ18d8Y_jAy"
      },
      "outputs": [],
      "source": [
        "delete_dataset = True\n",
        "delete_model = True\n",
        "delete_endpoint = True\n",
        "delete_pipeline = True\n",
        "delete_batchjob = True\n",
        "delete_edge_model = True\n",
        "delete_edge_pipeline = True\n",
        "delete_bucket = True\n",
        "\n",
        "# Delete the dataset using the Vertex AI fully qualified identifier for the dataset\n",
        "try:\n",
        "    if delete_dataset:\n",
        "        clients[\"dataset\"].delete_dataset(name=dataset_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the model using the Vertex AI fully qualified identifier for the model\n",
        "try:\n",
        "    if delete_model:\n",
        "        clients[\"model\"].delete_model(name=model_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the endpoint using the Vertex AI fully qualified identifier for the endpoint\n",
        "try:\n",
        "    if delete_endpoint:\n",
        "        clients[\"endpoint\"].delete_endpoint(name=endpoint_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the training pipeline using the Vertex AI fully qualified identifier for the training pipeline\n",
        "try:\n",
        "    if delete_pipeline:\n",
        "        clients[\"pipeline\"].delete_training_pipeline(name=training_pipeline_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the batch job using the Vertex AI fully qualified identifier for the batch job\n",
        "try:\n",
        "    if delete_batchjob:\n",
        "        clients[\"job\"].delete_batch_prediction_job(name=batch_job_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the Edge model using the Vertex AI fully qualified identifier for the Edge model\n",
        "try:\n",
        "    if delete_edge_model:\n",
        "        clients[\"model\"].delete_model(name=model_edge_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "# Delete the Edge training pipeline using the Vertex AI fully qualified identifier for the Edge training pipeline\n",
        "try:\n",
        "    if delete_edge_pipeline:\n",
        "        clients[\"pipeline\"].delete_training_pipeline(name=training_pipeline_edge_id)\n",
        "except Exception as e:\n",
        "    print(e)\n",
        "\n",
        "\n",
        "if delete_bucket and \"BUCKET_NAME\" in globals():\n",
        "    ! gsutil rm -r gs://$BUCKET_NAME"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "gcp_authenticate",
        "bucket:batch_prediction",
        "setup_vars",
        "import_aip",
        "aip_constants",
        "automl_constants:automl"
      ],
      "name": "UJ1 unified AutoML Vision Image Classification.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
